package com.snack.shop.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.snack.shop.common.BusinessException;
import com.snack.shop.config.WechatMiniappConfig;
import com.snack.shop.dto.LoginParam;
import com.snack.shop.dto.WxLoginResponse;
import com.snack.shop.dto.UserUpdateRequest;
import com.snack.shop.dto.WxLoginParam;
import com.snack.shop.dto.RegisterParam;
import com.snack.shop.entity.User;
import com.snack.shop.mapper.UserMapper;
import com.snack.shop.service.UserService;
import com.snack.shop.utils.WxDecryptUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.transaction.annotation.Transactional;
import java.util.Map;
import java.util.HashMap;

/**
 * 用户服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;
    private final WechatMiniappConfig wechatMiniappConfig;
    private final RestTemplate restTemplate;

    @Override
    public String login(LoginParam param) {
        // 查询用户
        User user = getUserByPhone(param.getPhone());
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 验证密码（前端已经MD5加密，直接比对）
        if (!param.getPassword().equals(user.getPassword())) {
            throw new BusinessException("密码错误");
        }

        // 检查状态
        if (user.getStatus() == 0) {
            throw new BusinessException("账号已被禁用");
        }

        // 登录
        StpUtil.login(user.getId());
        return StpUtil.getTokenValue();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String register(RegisterParam param) {
        if (param == null) {
            throw new BusinessException("参数不能为空");
        }
        String phone = param.getPhone() == null ? null : param.getPhone().trim();
        String password = param.getPassword() == null ? null : param.getPassword().trim();

        if (phone == null || phone.isEmpty()) {
            throw new BusinessException("手机号不能为空");
        }
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new BusinessException("手机号格式不正确");
        }
        if (password == null || password.isEmpty()) {
            throw new BusinessException("密码不能为空");
        }
        // 前端已MD5加密，这里校验长度为32位
        if (password.length() != 32) {
            throw new BusinessException("密码格式不正确");
        }

        // 校验手机号唯一
        User existed = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phone));
        if (existed != null) {
            throw new BusinessException("该手机号已注册");
        }

        // 组装用户数据并保存
        User user = new User();
        user.setPhone(phone);
        user.setPassword(password);
        user.setUserType(1); // 普通用户
        user.setStatus(1);   // 启用
        user.setGender(0);   // 未知
        String nickname = "用户";
        if (phone.length() >= 7) {
            nickname = "用户" + phone.substring(phone.length() - 4);
        }
        user.setNickname(nickname);

        userMapper.insert(user);

        // 自动登录并返回token
        StpUtil.login(user.getId());
        return StpUtil.getTokenValue();
    }

    @Override
    public void updateProfile(Long userId, UserUpdateRequest request) {
        if (userId == null) {
            throw new BusinessException("未登录");
        }
        User u = userMapper.selectById(userId);
        if (u == null) {
            throw new BusinessException("用户不存在");
        }

        // 昵称
        if (request.getNickname() != null && !request.getNickname().trim().isEmpty()) {
            u.setNickname(request.getNickname().trim());
        }
        // 头像
        if (request.getAvatar() != null && !request.getAvatar().trim().isEmpty()) {
            u.setAvatar(request.getAvatar().trim());
        }
        // 性别
        if (request.getGender() != null) {
            Integer g = request.getGender();
            if (g < 0 || g > 2) {
                throw new BusinessException("性别参数不合法");
            }
            u.setGender(g);
        }
        // 手机号（可选校验唯一）
        if (request.getPhone() != null && !request.getPhone().trim().isEmpty()) {
            String phone = request.getPhone().trim();
            User existed = userMapper.selectOne(new LambdaQueryWrapper<User>()
                    .eq(User::getPhone, phone));
            if (existed != null && !existed.getId().equals(userId)) {
                throw new BusinessException("手机号已被占用");
            }
            u.setPhone(phone);
        }
        
        // 密码修改（需要验证原密码）
        if (request.getOldPassword() != null && !request.getOldPassword().trim().isEmpty() &&
            request.getNewPassword() != null && !request.getNewPassword().trim().isEmpty()) {
            String oldPassword = request.getOldPassword().trim();
            String newPassword = request.getNewPassword().trim();
            
            // 验证原密码是否正确
            if (!u.getPassword().equals(oldPassword)) {
                throw new BusinessException("原密码错误");
            }
            
            // 验证新密码长度
            if (newPassword.length() < 32) {
                throw new BusinessException("新密码格式不正确");
            }
            
            // 更新密码
            u.setPassword(newPassword);
        }

        userMapper.updateById(u);
    }

    @Override
    public User getUserById(Long userId) {
        return userMapper.selectById(userId);
    }

    @Override
    public User getUserByPhone(String phone) {
        return userMapper.selectOne(
            new LambdaQueryWrapper<User>()
                .eq(User::getPhone, phone)
        );
    }
    
    @Override
    public String getAndSaveOpenid(String code) {
        try {
            // 调用微信接口获取openid
            String url = String.format(
                "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                wechatMiniappConfig.getAppId(),
                wechatMiniappConfig.getAppSecret(),
                code
            );
            
            log.info("调用微信接口获取openid，url: {}", url);
            
            WxLoginResponse response = restTemplate.getForObject(url, WxLoginResponse.class);
            
            if (response == null) {
                throw new BusinessException("调用微信接口失败");
            }
            
            if (response.getErrcode() != null && response.getErrcode() != 0) {
                log.error("获取openid失败，errcode: {}, errmsg: {}", response.getErrcode(), response.getErrmsg());
                throw new BusinessException("获取openid失败：" + response.getErrmsg());
            }
            
            String openid = response.getOpenid();
            if (openid == null || openid.isEmpty()) {
                throw new BusinessException("获取到的openid为空");
            }
            
            log.info("获取openid成功: {}", openid);
            
            // 获取当前登录用户ID
            Long userId = StpUtil.getLoginIdAsLong();
            
            // 更新用户的openid（避免 uk_openid 冲突）
            User user = userMapper.selectById(userId);
            if (user == null) {
                throw new BusinessException("用户不存在");
            }
            
            // 若该 openid 已被其他账号绑定，则直接返回，不再更新当前账号，避免唯一索引冲突
            User existed = userMapper.selectOne(
                new LambdaQueryWrapper<User>().eq(User::getOpenid, openid)
            );
            if (existed != null && !existed.getId().equals(userId)) {
                log.warn("openid 已绑定至其他账号，openid={}, existedUserId={}, currentUserId={}", openid, existed.getId(), userId);
                return openid;
            }
            
            // 如果当前用户已绑定相同 openid，直接返回
            if (openid.equals(user.getOpenid())) {
                return openid;
            }
            
            user.setOpenid(openid);
            userMapper.updateById(user);
            
            log.info("保存openid成功，userId: {}, openid: {}", userId, openid);
            
            return openid;
            
        } catch (Exception e) {
            log.error("获取并保存openid失败", e);
            throw new BusinessException("获取openid失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> wxLogin(WxLoginParam param) {
        try {
            // 调用微信接口获取openid
            String url = String.format(
                "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                wechatMiniappConfig.getAppId(),
                wechatMiniappConfig.getAppSecret(),
                param.getCode()
            );
            
            log.info("微信一键登录：调用微信接口获取openid");
            
            WxLoginResponse response = restTemplate.getForObject(url, WxLoginResponse.class);
            
            if (response == null) {
                throw new BusinessException("调用微信接口失败");
            }
            
            if (response.getErrcode() != null && response.getErrcode() != 0) {
                log.error("获取openid失败，errcode: {}, errmsg: {}", response.getErrcode(), response.getErrmsg());
                throw new BusinessException("获取openid失败：" + response.getErrmsg());
            }
            
            String openid = response.getOpenid();
            if (openid == null || openid.isEmpty()) {
                throw new BusinessException("获取到的openid为空");
            }
            
            log.info("微信一键登录：获取openid成功: {}", openid);
            
            // 获取手机号（如果提供了加密数据）
            String phoneNumber = null;
            if (param.getEncryptedData() != null && param.getIv() != null && response.getSessionKey() != null) {
                try {
                    // 使用sessionKey解密手机号
                    String decryptedData = WxDecryptUtil.decrypt(param.getEncryptedData(), response.getSessionKey(), param.getIv());
                    
                    // 解析JSON获取手机号
                    ObjectMapper objectMapper = new ObjectMapper();
                    JsonNode jsonNode = objectMapper.readTree(decryptedData);
                    phoneNumber = jsonNode.get("phoneNumber").asText();
                    
                    log.info("微信一键登录：手机号解密成功: {}", phoneNumber);
                } catch (Exception e) {
                    log.warn("微信一键登录：手机号解密失败: {}", e.getMessage());
                }
            }
            
            // 查询是否已存在该openid的用户
            User existingUser = userMapper.selectOne(
                new LambdaQueryWrapper<User>().eq(User::getOpenid, openid)
            );
            
            User user;
            boolean isNewUser = false;
            if (existingUser != null) {
                // 用户已存在，直接使用
                user = existingUser;
                log.info("微信一键登录：用户已存在，userId: {}", user.getId());
            } else {
                // 用户不存在，创建新用户
                user = new User();
                user.setOpenid(openid);
                user.setNickname(param.getNickName() != null ? param.getNickName() : "微信用户");
                user.setAvatar(param.getAvatarUrl());
                user.setGender(param.getGender() != null ? param.getGender() : 0);
                user.setPhone(phoneNumber); // 设置手机号（可能为null）
                // 密码：默认为12345678
                user.setPassword("25d55ad283aa400af464c76d713c07ad"); // MD5("12345678")
                user.setUserType(1); // 普通用户
                user.setStatus(1); // 正常状态
                
                userMapper.insert(user);
                isNewUser = true;
                log.info("微信一键登录：创建新用户成功，userId: {}, openid: {}, phone: {}", user.getId(), openid, phoneNumber);
            }
            
            // 登录
            StpUtil.login(user.getId());
            String token = StpUtil.getTokenValue();
            
            log.info("微信一键登录：登录成功，userId: {}", user.getId());
            
            // 返回登录结果和是否需要完善信息的标志
            Map<String, Object> result = new HashMap<>();
            result.put("token", token);
            result.put("needsInfo", isNewUser); // true表示新用户需要完善信息，false表示已存在的用户直接登录
            
            return result;
            
        } catch (BusinessException e) {
            log.error("微信一键登录失败", e);
            throw e;
        } catch (Exception e) {
            log.error("微信一键登录异常", e);
            throw new BusinessException("微信登录失败：" + e.getMessage());
        }
    }
}

